package com.wangshouyu.plugins.swagger;

import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.google.common.base.Optional;
import org.springframework.util.ReflectionUtils;
import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 王守钰
 * @date 2021-12-27 09:36
 * @description swagger枚举模型插件
 */
public class EnumModelPropertyBuilderPlugin implements ModelPropertyBuilderPlugin {

    /**
     * description列
     */
    private static final String DESCRIPTION_FIELD = "description";

    /**
     * 空字符串
     */
    private static final String EMPTY_STR = "";

    /**
     * 分号
     */
    private static final String SEMICOLON = ";";

    /**
     * 冒号
     */
    private static final String COLON = ":";

    /**
     * 左括号
     */
    private static final String OPEN_PARENTHESIS = "(";

    /**
     * 右括号
     */
    private static final String CLOSE_PARENTHESIS = ")";

    @Override
    public void apply(ModelPropertyContext context) {
        Optional<BeanPropertyDefinition> optional = context.getBeanPropertyDefinition();
        if (optional.isPresent()) {
            try{
                AnnotatedField annotatedField = optional.get().getField();
                Field field = annotatedField.getAnnotated();
                addDescForEnum(context, field);
            }catch (Exception e){

            }
        }
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }

    private void addDescForEnum(ModelPropertyContext context, Field field) {
        SwaggerDisplayEnum annotation = field.getAnnotation(SwaggerDisplayEnum.class);
        if (annotation != null) {
            String key = annotation.key();
            String value = annotation.value();
            Class<?> enumClass = annotation.clazz();
            Object[] enumConstants = enumClass.getEnumConstants();
            List<String> displayValues = Arrays.stream(enumConstants)
                    .filter(Objects::nonNull)
                    .map(item -> {
                        Class<?> currentClass = item.getClass();
                        Object name = EMPTY_STR;
                        if(null == key || EMPTY_STR.equals(key.trim())){
                            name = String.valueOf(item);
                        }else{
                            Field indexField = ReflectionUtils.findField(currentClass, key);
                            ReflectionUtils.makeAccessible(indexField);
                            name = ReflectionUtils.getField(indexField, item);
                        }
                        Field descField = ReflectionUtils.findField(currentClass, value);
                        ReflectionUtils.makeAccessible(descField);
                        Object desc = ReflectionUtils.getField(descField, item);
                        return name + COLON + desc;

                    }).collect(Collectors.toList());
            ModelPropertyBuilder builder = context.getBuilder();
            Field descField = ReflectionUtils.findField(builder.getClass(), DESCRIPTION_FIELD);
            ReflectionUtils.makeAccessible(descField);
            String joinText = ReflectionUtils.getField(descField, builder)
                    + OPEN_PARENTHESIS + String.join(SEMICOLON, displayValues) + CLOSE_PARENTHESIS;
            builder.description(joinText);
        }
    }
}
